#pragma once

#include <string>
#include <functional>

#include "log.hpp"
extern Log log;

#include "socket.hpp"
#include "thread_pool.hpp"

class TCP_server
{
public:
    typedef std::function<void(int, const std::string, uint16_t)> func_t;
    typedef TCP_server self;
public:
    TCP_server()
        : _is_running(false)
    {}
private:
    TCP_server(const self&) = delete;
    self& operator=(const self&) = delete;
public:
    void init(uint16_t port)
    {
        _listen_socket.Create(SOCK_STREAM);
        _listen_socket.Bind(port);
        _listen_socket.Listen();
        _thread_pool.start();
    }

    void run(func_t func)
    {
        _is_running = true;
        while (_is_running)
        {
            std::string client_ip;
            uint16_t client_port;
            int sockfd = _listen_socket.Accept(client_ip, client_port);
            if (sockfd < 0)
                continue;
            std::function<void(void)> thread_func = std::bind(func, sockfd, std::move(client_ip), client_port);
            _thread_pool.push(thread_func);
        }
    }

    ~TCP_server()
    {
        _listen_socket.Close();
    }
private:
    Socket _listen_socket;
    bool _is_running;
#ifdef __TEST_DEBUG__
    ThreadPool<5> _thread_pool;
#else
    ThreadPool<> _thread_pool;
#endif
};
